class Item < ActiveRecord::Base

  has_many :check_ins, :dependent => :destroy
  belongs_to :client, :class_name => 'User'
  has_many :comments, :dependent => :destroy
  has_many :contained_items, :class_name => 'Item', :foreign_key => 'contained_by_id'
  belongs_to :contained_by, :class_name => 'Item'
  belongs_to :source, :class_name => 'Location'
  belongs_to :destination, :class_name => 'Location'
  has_many :identifiers, :dependent => :destroy
  has_many :item_attribute_values
  has_many :item_attributes, :through => :item_attribute_values
  has_one :lost_item, :dependent => :destroy
  belongs_to :item_type
  belongs_to :carried_by, :class_name => 'Courier'  
  has_one :replacement, :class_name => 'Item', :foreign_key => 'replaced_id'
  belongs_to :replaced, :class_name => 'Item'

  accepts_nested_attributes_for :item_attribute_values
  accepts_nested_attributes_for :comments, :reject_if => :reject_comment
  accepts_nested_attributes_for :identifiers

  validates_presence_of :client
  validates_associated :contained_items
  validate :has_required_attribute_sets
  validates_presence_of :item_type
  validate :has_source, :has_destination

  before_validation :pass_to_contained_items
  before_validation :verify_identifier
  before_validation :create_item_checkin
  before_validation :clear_non_container_items

  def display_name
	type = item_type ? item_type.item_type : "Item"
	identifier = (identifiers.first and identifiers.first.identifier_value) ? identifiers.first.identifier_value : "No ID"
	
	type + " " + identifier
  end
  
  def is_container(x)
    if item_type
	  item_type.is_container == x
	else
	  false
	end
  end
  
  def contained_item_attributes=(item_attributes)
    item_attributes.each do |attributes|
	  contained_items.build(attributes)
	end
  end
  
private

  Characters = [(0..9),('a'..'z'),('A'..'Z')].map{|n| n.to_a}.flatten

  def reject_comment(attributes)
    attributes['text'].blank?
  end
  
  def has_required_attribute_sets
    required_ias = ItemAttributeSet.find_all_by_required(true)
	item_attribute_sets = item_attribute_values.map { |iav| 
		ia = iav.item_attribute
		if ia
			ia.item_attribute_set
		end
	}
	(required_ias - item_attribute_sets).each do |set|
	  errors.add_to_base(set.name + ' is required')
	end
  end
  
  def has_source
    errors.add(:source, "Need a source") if source.nil?
  end
  
  def has_destination
    errors.add(:destination, "Need a destination") if destination.nil?
  end
  
  def pass_to_contained_items
 	contained_items.each do |i|
	  if i.new_record?
	    i.destination = destination
		contained_iavs = i.item_attribute_values.map {|iav| iav.item_attribute_id}
	    item_attribute_values.each do |iav|
	      if iav.item_attribute and iav.item_attribute.item_attribute_set and iav.item_attribute.item_attribute_set.inherits_from_container
		    if not contained_iavs.include? iav.item_attribute_id
			  i.item_attribute_values << iav.clone
	        end
	      end
	    end
	  end
	end
  end
  
  def verify_identifier
	if (!identifiers.first)
	    # Make sure all items have an identifier
		identifiers << Identifier.new
		identifiers.first.identifier_type = 'barcode'
	end
	if identifiers.first.identifier_value.to_s.length == 0
		# Generate ids for these items
		identifiers.first.identifier_value = (0..8).map{ Characters.rand }.join
	end
  end

  def create_item_checkin
	if self.new_record? and not check_ins.any?
		# Only create one checkin for new items
		check_ins.build(:location => source, :user => client, :action => "initial_checkin", :item => self)
	end
  end
  
  def clear_non_container_items
	# If not a container, should clear all the contained items (generated by form)
	if (!item_type or !item_type.is_container)
		contained_items.clear
	end
  end
end
